package com.vnie.mina.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

import com.vnie.mina.message.BaseMessage;
import com.vnie.mina.message.VConstant;

public class Util {

	private static Logger log = Logger.getLogger(Util.class);

	/**
	 * �?16进制字符串转换成字节数组
	 * 
	 * @param hex
	 * @return
	 */
	public static byte[] hexStringToByte(String hex) {
		int len = (hex.length() / 2);
		byte[] result = new byte[len];
		char[] achar = hex.toCharArray();
		for (int i = 0; i < len; i++) {
			int pos = i * 2;
			result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
		}
		return result;
	}

	private static byte toByte(char c) {
		byte b = (byte) "0123456789ABCDEF".indexOf(c);
		return b;
	}

	/**
	 * 把字节数组转换成16进制字符�?
	 * 
	 * 
	 * @param bArray
	 * @return
	 */
	public static final String bytesToHexString(byte[] bArray) {
		StringBuffer sb = new StringBuffer(bArray.length);
		String sTemp;
		for (int i = 0; i < bArray.length; i++) {
			sTemp = Integer.toHexString(0xFF & bArray[i]);
			if (sTemp.length() < 2)
				sb.append(0);
			sb.append(sTemp.toUpperCase());
		}
		return sb.toString();
	}

	/**
	 * 把字节数组转换为对象
	 * 
	 * @param bytes
	 * @return
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public static final Object bytesToObject(byte[] bytes) throws IOException,
			ClassNotFoundException {
		ByteArrayInputStream in = new ByteArrayInputStream(bytes);
		ObjectInputStream oi = new ObjectInputStream(in);
		Object o = oi.readObject();
		oi.close();
		return o;
	}

	/**
	 * 把可序列化对象转换成字节数组
	 * 
	 * @param s
	 * @return
	 * @throws IOException
	 */
	public static final byte[] objectToBytes(Serializable s) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ObjectOutputStream ot = new ObjectOutputStream(out);
		ot.writeObject(s);
		ot.flush();
		ot.close();
		return out.toByteArray();
	}

	public static final String objectToHexString(Serializable s)
			throws IOException {
		return bytesToHexString(objectToBytes(s));
	}

	public static final Object hexStringToObject(String hex)
			throws IOException, ClassNotFoundException {
		return bytesToObject(hexStringToByte(hex));
	}

	/**
	 * @函数功能: BCD码转�?10进制�?(阿拉伯数�?)
	 * @输入参数: BCD�?
	 * 
	 * @输出结果: 10进制�?
	 */
	public static String bcd2Str(byte[] bytes) {
		StringBuffer temp = new StringBuffer(bytes.length * 2);

		for (int i = 0; i < bytes.length; i++) {
			temp.append((byte) ((bytes[i] & 0xf0) >>> 4));
			temp.append((byte) (bytes[i] & 0x0f));
		}
		// return temp.toString().substring(0, 1).equalsIgnoreCase("0") ?
		// temp.toString().substring(1) : temp.toString();
		return temp.toString();
	}

	/**
	 * @函数功能: 10进制串转为BCD�?
	 * 
	 * @输入参数: 10进制�?
	 * 
	 * @输出结果: BCD�?
	 */
	public static byte[] str2Bcd(String asc) {
		int len = asc.length();
		int mod = len % 2;

		if (mod != 0) {
			asc = "0" + asc;
			len = asc.length();
		}

		byte[] abt = new byte[len];

		if (len >= 2) {
			len = len / 2;
		}

		byte[] bbt = new byte[len];

		abt = asc.getBytes();
		int j, k;

		for (int p = 0; p < asc.length() / 2; p++) {
			if ((abt[2 * p] >= '0') && (abt[2 * p] <= '9')) {
				j = abt[2 * p] - '0';
			} else if ((abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) {
				j = abt[2 * p] - 'a' + 0x0a;
			} else {
				j = abt[2 * p] - 'A' + 0x0a;
			}

			if ((abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) {
				k = abt[2 * p + 1] - '0';
			} else if ((abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) {
				k = abt[2 * p + 1] - 'a' + 0x0a;
			} else {
				k = abt[2 * p + 1] - 'A' + 0x0a;
			}

			int a = (j << 4) + k;
			byte b = (byte) a;
			bbt[p] = b;
		}
		return bbt;
	}

	public final static char[] BToA = "0123456789abcdef".toCharArray();

	/**
	 * @函数功能: BCD码转ASC�?
	 * 
	 * @输入参数: BCD�?
	 * 
	 * @输出结果: ASC�?
	 */
	public static String BCD2ASC(byte[] bytes) {
		StringBuffer temp = new StringBuffer(bytes.length * 2);

		for (int i = 0; i < bytes.length; i++) {
			int h = ((bytes[i] & 0xf0) >>> 4);
			int l = (bytes[i] & 0x0f);
			temp.append(BToA[h]).append(BToA[l]);
		}
		return temp.toString();
	}

	/**
	 * MD5加密字符串，返回加密后的16进制字符�?
	 * 
	 * 
	 * @param origin
	 * @return
	 */
	public static String MD5EncodeToHex(String origin) {
		return bytesToHexString(MD5Encode(origin));
	}

	/**
	 * MD5加密字符串，返回加密后的字节数组
	 * 
	 * @param origin
	 * @return
	 */
	public static byte[] MD5Encode(String origin) {
		return MD5Encode(origin.getBytes());
	}

	/**
	 * MD5加密字节数组，返回加密后的字节数�?
	 * 
	 * 
	 * @param bytes
	 * @return
	 */
	public static byte[] MD5Encode(byte[] bytes) {
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("MD5");
			return md.digest(bytes);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return new byte[0];
		}

	}

	/**
	 * 将int转为低字节在前，高字节在后的int
	 */
	public static int tolh(int in) {
		int out = 0;
		out = (in & 0xff) << 24;
		out |= (in & 0xff00) << 8;
		out |= (in & 0xff0000) >> 8;
		out |= (in & 0xff000000) >> 24;
		return out;
	}

	/**
	 * 将float转为低字节在前，高字节在后的int
	 */
	public static int tolh(float f) {
		return tolh((int) f);
	}

	/**
	 * 
	 * @param bt
	 * @return
	 */
	public static int byteToInt(byte bt) {
		int i = bt - 48;
		return i;
	}

	/**
	 * 
	 * 
	 * @param bt
	 * @return
	 */

	public static int byteToInt(byte[] bt) {

		int in = (bt[0] & 0xff) | ((bt[0] << 8) & 0xff00)
				| ((bt[0] << 24) >>> 8) | (bt[0] << 24);

		return in;

	}

	// public static byte[] intToByte(int in) {
	// byte[] bt = new byte[4];
	// bt[0] = (byte) (in & 0xff);
	// bt[1] = (byte) ((in >> 8) & 0xff);
	// bt[2] = (byte) ((in >> 16) & 0xff);
	// bt[3] = (byte) (in >>> 24);
	// return bt;
	// }

	public static byte[] intToByte(int in) {
		String str_in = String.valueOf(in);
		byte[] byte_in = str_in.getBytes();
		byte[] ret_byte = new byte[byte_in.length];
		for (int i = 0; i < ret_byte.length; i++) {
			ret_byte[i] = (byte) (byte_in[i] - (byte) 0x30);
		}
		return ret_byte;
	}

	public static byte[] shortToByte(short in) {
		byte[] bt = new byte[2];
		bt[1] = (byte) (in & 0xff);
		bt[0] = (byte) (in >>> 8);
		return bt;
	}

	/**
	 * 十进制转换为十六进制
	 * 
	 * @param dec
	 *            int
	 * @return String
	 */
	public static String dec2Hex(int dec) {

		StringBuffer sb = new StringBuffer();

		sb.append("0x");

		for (int i = 0; i < 8; i++) {
			int tmp = (dec >> (7 - i % 8) * 4) & 0x0f;

			if (tmp < 10)
				sb.append(tmp);
			else
				sb.append((char) ('A' + (tmp - 10)));
		}

		return sb.toString();
	}

	/**
	 * 
	 * @param dec
	 * @return hex Integer
	 * 
	 */

	public static int dec2Hex2(int dec) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < 8; i++) {
			int tmp = (dec >> (7 - i % 8) * 4) & 0x0f;
			if (tmp < 10)
				sb.append(tmp);
			else
				sb.append((char) ('A' + (tmp - 10)));
		}

		return Integer.parseInt(sb.toString());
	}

	/**
	 * byte转换为十六进�?
	 * 
	 * 
	 * @param b
	 *            byte
	 * @return String
	 */
	public static String byte2Hex(byte b) {
		return ("" + "0123456789ABCDEF".charAt(0xf & b >> 4) + "0123456789ABCDEF"
				.charAt(b & 0xf));
	}

	/*
	 * 
	 */
	public static void writeLog(byte[] bt) {
		writeLog(bt, "  ");
	}

	/*
	 * 
	 */
	public static void writeLog(byte[] bt, String message) {

		try {
			SimpleDateFormat df = new SimpleDateFormat("yyMMdd");
			File file = new File("MinaClient" + df.format(new Date()) + ".txt");

			if (!file.exists())
				file.createNewFile();

			byte[] enter = new byte[2];
			enter[0] = 0x0d;
			enter[1] = 0x0a;// 用于输入换行符的字节�?

			String hint = "=" + new Date() + " " + message + "=";

			FileOutputStream fout = new FileOutputStream(file, true);
			fout.write(hint.getBytes());
			fout.write(enter);

			for (int i = 0; i < bt.length; i++) {
				if (i % 16 == 0) {
					fout.write(enter);
				}

				fout.write(Util.byte2Hex(bt[i]).getBytes());
				fout.write(" ".getBytes());
			}

			fout.write(enter);
			fout.write(enter);
			fout.close();

		} catch (FileNotFoundException e) {
			log.info("日志记录" + e.getMessage());
		} catch (IOException e) {
			log.info("日志记录" + e.getMessage());
		}
	}

	/**
	 * 取银行报文字�?
	 * 
	 * @param pContent
	 * @param index
	 * @return
	 */
	public static byte[] getField(byte[] pContent, int index) {
		byte[] field;
		int pLength = pContent.length;
		int fLength;
		int begin = 0;
		int end = 0;
		int count = 0;
		if (index == 1) {
			for (int i = 0; i < pLength; i++) {
				end = 0;
				if (pContent[i] == '|') {
					count++;
				}
				if (count == index) {
					end = i;
					break;
				}
			}
			fLength = end - begin;
			field = new byte[fLength];
			System.arraycopy(pContent, begin, field, 0, fLength);
		}
		// else if(index == 16){
		// end = pContent.length;
		// for (int i = 0;i<pLength; i++) {
		// if (pContent[i] == '|') {
		// count++;
		// if (count == index-1) {
		// begin = i+1;
		// break;
		// }
		// }
		//
		// }
		// fLength = end - begin;
		// field = new byte[fLength];
		// System.arraycopy(pContent, begin, field, 0, fLength);
		// }
		else {
			for (int i = 0; i < pLength; i++) {
				if (pContent[i] == '|') {
					count++;
					if (count == (index - 1)) {
						begin = i + 1;
					} else if (count == index) {
						end = i;
						break;
					}
				}

			}
			fLength = end - begin;
			field = new byte[fLength];
			System.arraycopy(pContent, begin, field, 0, fLength);
		}
		return field;
	}

	/**
	 * 整形转换成byte数组只返回低位两个字�?
	 * 
	 * @param value
	 * @return
	 */
	public static byte[] getBytes(int mTotalLength) {
		int value = mTotalLength;
		byte[] bs = { 0x00, 0x00 };
		bs[0] = new Integer((value & 0xff00) >> 8).byteValue(); // 把最高位�?个字节保存到数组�?
		bs[1] = new Integer((value & 0x00ff)).byteValue();
		return bs;
	}

	/*
	 * 六位数字
	 */
	public static int ByteBCDtoInt(byte[] bt) {
		int sum = 0;
		int length = bt.length, j = 0;
		for (int i = 0; i < length; i++) {
			sum += ((((bt[i] >> 4) & 0x0f) * 10 + (bt[i] & 0x0f)))
					* Math.pow(10, length * 2 - j + 1);
			j += 2;
		}
		return sum;
	}

	public static int ByteBCDtoInt(byte bt) {
		int sum = bt;
		return (sum / 16) * 10 + sum % 16;
	}

	/*
	 * 12位的数字
	 */
	public static long ByteBCDtoInt6(byte[] bt) {
		long sum = 0;
		int length = bt.length, j = 1;
		for (int i = 0; i < length; i++) {
			sum += ((((bt[i] >> 4) & 0x0f) * 10 + (bt[i] & 0x0f)))
					* Math.pow(10, length * 2 - j * 2);
			j += 1;
		}

		return sum;
	}

	/**
	 * 构建字节数组，多余部分以0x00补齐
	 * 
	 * @param dest
	 * @param src
	 * @return
	 */
	public static byte[] fillArea(byte[] dest, String src) {
		byte[] bytes = Util.str2Bcd(src);
		System.arraycopy(bytes, 0, dest, 0, bytes.length);
		for (int i = bytes.length; i < dest.length; i++) {
			dest[i] = 0x00;
		}
		return dest;
	}

	public static byte[] fillArea(byte[] dest, int src) {
		byte[] bytes = Util.intToByte(src);
		System.arraycopy(bytes, 0, dest, 0, bytes.length);
		for (int i = bytes.length; i < dest.length; i++) {
			dest[i] = 0x00;
		}
		return dest;
	}

	public static byte[] buildTLV(int tag, String value)
			throws UnsupportedEncodingException {

		// 1ExtendBit+1CompressBit+6TagBit(长度2字节，不压缩)
		byte tagByte = (byte) (0x80 | tag);
		byte[] lengthByte = shortToByte((short) value.length());
		byte[] valueByte = value.getBytes(VConstant.ASCII);
		int length = 1 + 2 + valueByte.length;

		byte[] retByte = new byte[length];
		retByte[0] = tagByte;
		System.arraycopy(lengthByte, 0, retByte, 1, lengthByte.length);
		System.arraycopy(valueByte, 0, retByte, 3, valueByte.length);
		return retByte;
	}

	public static byte[] buildTLV(int tag, byte[] value)
			throws UnsupportedEncodingException {

		// 1ExtendBit+1CompressBit+6TagBit(长度2字节，不压缩)
		byte tagByte = (byte) (0x80 | tag);
		byte[] lengthByte = shortToByte((short) value.length);
		byte[] valueByte = value;
		int length = 1 + 2 + valueByte.length;

		byte[] retByte = new byte[length];
		retByte[0] = tagByte;
		System.arraycopy(lengthByte, 0, retByte, 1, lengthByte.length);
		System.arraycopy(valueByte, 0, retByte, 3, valueByte.length);
		return retByte;
	}

	/**
	 * 解包tlv报文格式
	 * 
	 * @param entity
	 * @return
	 */
	public static Map<String, Object> unpackTLV(byte[] entity) {
		byte tagbit = entity[0];
		boolean bcd = false;
		Map<String, Object> retMap = new HashMap<String, Object>();
		// 一个字节表示长度
		if ((tagbit & (byte) 0x00) == (byte) 0x00) {
			// 如果第一个字节第二位为1,则为bcd压缩
			if ((tagbit & (byte) 0x40) == (byte) 0x40) {
				bcd = true;
			}
			int tag = tagbit & (byte) 0x3f;
			int length = entity[1];
			byte[] value = new byte[length];
			retMap.put("tag", tag);
			retMap.put("length", (int) length);
			retMap.put("value", value);
			retMap.put("bcd", bcd);
			// magic number 2 为一个字节tagbit和表示长度的一个字节
			System.arraycopy(entity, 2, value, 0, length);
			// 截掉已经解析过的报文
			byte[] newEntity = new byte[entity.length - length - 2];
			int cutLength = 2 + length;
			System.arraycopy(entity, cutLength, newEntity, 0, entity.length
					- cutLength);
			retMap.put("entity", newEntity);
		}
		return retMap;
	}

	public static byte[] buildMac(byte[] entity, int count) {
		if (count < 8)
			throw new IllegalArgumentException("ooP,maybe too short!");
		byte[] mac = new byte[8];
		byte[] slicedmac = new byte[8];
		byte[] newEntity = entity;
		System.arraycopy(entity, 0, mac, 0, 8);
		if (count % 8 != 0) {
			int origCount = count;
			count += 8 - (count % 8);
			byte[] extendEntity = new byte[count];
			Arrays.fill(extendEntity, (byte) 0x00);
			System.arraycopy(entity, 0, extendEntity, 0, origCount);
			newEntity = extendEntity;
		}
		for (int i = 8; i < count; i++) {
			if ((i + 1) % 8 == 0) {
				System.arraycopy(newEntity, i - 7, slicedmac, 0, 8);
				for (int j = 0; j < 8; j++) {
					mac[j] = (byte) (mac[j] ^ slicedmac[j]);
				}
			}
		}
		return mac;
	}

	public static void main(String[] args) {
		// byte[] test = {0x00, 0x02, 0x30, 0x30};
		// Map<String,Object> map = unpackTLV(test);
		// int tag = (Integer)map.get("tag");
		// int length = (Integer)map.get("length");
		// byte[] value = (byte[])map.get("value");
		int i = 1209832;
		byte[] b = intToByte(i);
		// byte[] test = new
		// byte[]{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00};
		// byte[] mac = buildMac(test, test.length);
		// try {
		// System.out.println(bytesToHexString(buildTLV(5, "23")));
		// } catch (UnsupportedEncodingException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
	}

}
